'use strict';
const fs = require("fs");
const path = require("path");
const template = require("lodash.template");

/**
 * Load options from config file, use default if config file not exists.
 * @returns {{defineFilePrefix: string, templatePattern: RegExp, templates: [string]}}
 */
function loadOptions(cmd) {
  //Default options
  let options = {"defineFilePrefix": ".variables", "templatePattern": /(.+)\.tpl(\.[\w_]+)$/i, "templates": ["config"]};
  const configFile = path.resolve(process.cwd(), "env-replacer.config.json");
  if (fs.existsSync(configFile)) {
    const configStr = fs.readFileSync(configFile, "utf-8");
    const configJson = JSON.parse(configStr);
    if (configJson.hasOwnProperty("templatePattern")) configJson.templatePattern = new RegExp(configJson.templatePattern);
    options = Object.assign(options, configJson);
  }
  return Object.assign(options, cmd);
}

/**
 * parse variables file to variables object.
 * @param variablesFile
 * @returns {null|object}
 */
function parseVariablesFile(variablesFile) {
  const actualFile = variablesFile + ".json";
  if (fs.existsSync(actualFile)) {
    const configStr = fs.readFileSync(actualFile, "utf-8");
    return JSON.parse(configStr);
  }
  return null;
}

/**
 * Load variables from file and environment variable
 * @param options
 * @returns {object} Variables object
 * */
function loadVariables(options) {
  const modeVariables = options.mode ? parseVariablesFile(`${options.defineFilePrefix}.${options.mode}`) : null;
  const modelLocalVariables = options.mode ? parseVariablesFile(`${options.defineFilePrefix}.${options.mode}.local`) : null;
  const variables = parseVariablesFile(options.defineFilePrefix);
  const localVariables = parseVariablesFile(`${options.defineFilePrefix}.local`);
  const envVariable = process.env;
  return Object.assign({}, variables, localVariables, modeVariables, modelLocalVariables, envVariable);
}

/**
 * Scan folder or file and compile.
 * @param filePath folder or file path
 * @param options Global options
 * @param variables variables object
 */
function scanFile(filePath, options, variables) {
  const stat = fs.statSync(filePath);
  if (stat.isDirectory()) {
    fs.readdir(filePath, "utf8", (err, files) => {
      files.forEach(oneFile => scanFile(path.join(filePath, oneFile), options, variables));
    });
  } else if (stat.isFile() && options.templatePattern.test(filePath)) {
    compileFile(filePath, options, variables)
  }
}

/**
 * Compile template file.
 * @param file Template file
 * @param options Global options
 * @param variables Usable variables object
 */
function compileFile(file, options, variables) {
  fs.readFile(file, "utf-8", (err, res) => {
    if (!err) {
      const code = template(res)(variables);
      fs.writeFile(file.replace(options.templatePattern, "$1$2"), code, err1 => err1 && console.log(err1));
    }
  });
}

/**
 * Parse command line arguments.
 * @param args
 * @returns {{}}
 */
function parseArgs(args) {
  return args.filter(x => x.startsWith("--")).reduce((r, it) => {
    if (it.length > 2) {
      const splitIndex = it.indexOf("=");
      if (splitIndex > 2) {
        const k = it.substring(2, splitIndex);
        r[k] = it.substring(splitIndex + 1);
      } else {
        const k = it.substring(2);
        r[k] = true;
      }
      return r;
    }
    if (it.length === 1) {
      r[it] = true;
    } else if (it.length >= 2) {

    }
  }, {})
}

/**
 * Apply env replacer
 */
function apply(args) {
  const cmdOptions = parseArgs(args);
  const options = loadOptions(cmdOptions);
  const variables = loadVariables(options);
  options.templates.forEach(filePath => {
    scanFile(filePath, options, variables);
  });
}

module.exports = apply;
